import java.io.File;
import java.util.Date;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;

import com.almworks.sqlite4java.SQLiteConnection;
import com.almworks.sqlite4java.SQLiteException;
import com.almworks.sqlite4java.SQLiteStatement;


public class LocationDBParser {
	
	private final static String jp1 = "redpin_JP1_24_12_2012.db";
	//private final static String dcc1 = "redpin_daycare_centre_24_12_2012.db";
	//private final static String dcc2 = "redpin_daycare_centre_3_01_2013.db";
	
	private final static int pLocomotionPhase = 15;
	private final static int ambulationEpisode = (5 * 60) + 41;
	
	private static Date patient1EndTime;
	private static Date patient2EndTime;
	private static Date patient3EndTime;
	private static Date patient4EndTime;
	private static Date patient5EndTime;
	
	private static ArrayList<Location> allTrips;
	
	private static SQLiteConnection db;
	private static SQLiteStatement st;
	
	private static Location tempLocation;
	
	public LocationDBParser() throws SQLiteException 
	{
		
	}
	
	/**
	 * @param args
	 * @throws SQLiteException 
	 * @throws ParseException 
	 */
	public static void main(String[] args) throws SQLiteException, ParseException 
	{
		setDates();
		
		allTrips = new ArrayList<Location>();
		
		db = new SQLiteConnection(new File("C://Users//colin//Documents//Magic Briefcase//MSc Documents//Research Thesis//Pilot Study//"+jp1));
		db.open(true);
		    
		st = db.prepare("SELECT loc.symbolicId, v1.timestamp" + " FROM visitedlocation v1, location loc" + " WHERE v1.locationId = loc.locationId");
		
		try {
	    	
		      while (st.step()) 
		      {
		    	  	Date locDate = epochToDate(st.columnString(1));
		    	  	//if(locDate.after(patient2EndTime))
		    	  	//{
		    	  		tempLocation = new Location(st.columnString(0), st.columnLong(1));
		    	  		allTrips.add(tempLocation);
		    	  	//}
		      }
		}
		finally 
		{
		     st.dispose();
		}
		
		/*printArray(allTrips);
		System.out.println("-------------------");*/
		
		ArrayList<Location> locFiltered = filterUniqueTrips(allTrips);
		printArray(locFiltered);
		System.out.println("-------------------");
		
		ArrayList<Episode> patternFiltered = groupByPattern(locFiltered);
		printPatternArray(patternFiltered);
		System.out.println("-------------------");
		
		/*HashMap<Pattern, Integer> result = new HashMap<Pattern, Integer>();
		result = countTrips(patternFiltered);
		printHashMap(result);
		
		System.out.println("-------------------");
		printWithDate(allTrips);*/
		
		ArrayList<Episode> patterns = getTravelPatterns(allTrips);
	    printPatterns(patterns);
	}
	
	private static void printPatterns(ArrayList<Episode> patterns) 
	{
		for(Episode p : patterns)
		{
			ArrayList<Location> locations = p.getPattern();
			
			for(Location l : locations)
			{
				System.out.print(l.getName() + " : " + epochToDate(Long.toString(l.getTimestamp())) + " ");
			}
			
			System.out.println(" ");
		}
	}

	private static ArrayList<Episode> getTravelPatterns(ArrayList<Location> allTrips)
	{
		ArrayList<Episode> allPatterns = new ArrayList<>();
		
		ArrayList<Location> patternList = new ArrayList<>();
		
		Location currentLocation = null;
		
		for(Location trip : allTrips)
		{
			if(currentLocation == null)
			{
				// First location in series
				currentLocation = trip;
			}
			else
			{
				if(!patternList.contains(currentLocation))
				{
					// Add currentLocation if not already in patternList
					patternList.add(currentLocation);
				}
				
				if(trip.getName().compareTo(currentLocation.getName()) == 0)
				{
					// Location is the same as currentLocation
					// Skip to next new location
				}
				else
				{
					// New location found
					// - Compare with currentLocation for 15s locomation phase
					// - Compare first location in patternList for 5.41min ambulation
					
					long locomotionPhase = compareTimeInSeconds(trip, currentLocation);
					
					patternList.add(trip);
					
					if(locomotionPhase < pLocomotionPhase)
					{						
						Location firstLoc = patternList.get(0);
						
						long ambulationTime = compareTimeInSeconds(trip, currentLocation);
						
						currentLocation = trip;
						
						if(ambulationTime > ambulationEpisode)
						{
							Episode p = new Episode();
							
							for(Location l : patternList)
							{
								p.addLocation(l);
							}
							
							allPatterns.add(p);
							
							currentLocation = trip;
							patternList.clear();
						}
						
					}
					else
					{
						// Locations longer than locomotion phase
						// New pattern set up with current locations
						
						Episode p = new Episode();
						
						for(Location l : patternList)
						{
							p.addLocation(l);
						}
						
						allPatterns.add(p);
						
						currentLocation = trip;
						patternList.clear();
					}
				}
			}
		}
		
		return allPatterns;
	}

	private static long compareTimeInSeconds(Location trip, Location currentLocation) 
	{
		long seconds = trip.getTimestamp() - currentLocation.getTimestamp();
		
		return seconds;
	}

	private static void printWithDate(ArrayList<Location> allTrips2) 
	{
		int x = 1;
		for(Location l : allTrips2)
		{
			System.out.println(x + " " + l.getName() + " : "  + epochToDate(Long.toString(l.getTimestamp(), 0)));
			x++;
		}
		
	}

	private static void setDates() throws ParseException 
	{
		SimpleDateFormat sdf = new SimpleDateFormat("dd-MMM-yyy HH:mm:ss");
		
		setPatient1EndTime(sdf.parse("24-Dec-2012 15:45:00"));
		patient2EndTime = sdf.parse("24-Dec-2012 16:15:00");
		patient3EndTime = sdf.parse("29-Dec-2012 13:00:00");
		patient4EndTime = sdf.parse("03-Jan-2013 12:50:00");
		patient5EndTime = sdf.parse("04-Jan-2013 12:30:00");
	}

	private static void printHashMap(HashMap<Episode, Integer> result) 
	{
		for(Episode p : result.keySet())
		{
			Integer amount = result.get(p);
			System.out.println(p.getFirstLocation().getName() + " " + p.getSecondLocation().getName() + " \t " + amount);
		}
	}

	private static void printArray(ArrayList<Location> allTrips2) 
	{
		for(Location e : allTrips2)
		{
			System.out.print(e.getName() + " ");
		}
	}
	
	private static void printPatternArray(ArrayList<Episode> allPatterns) 
	{
		for(Episode e : allPatterns)
		{
			System.out.println(e.getFirstLocation().getName() + " " + e.getSecondLocation().getName());
		}
	}

	private static ArrayList<Location> filterUniqueTrips(ArrayList<Location> allTrips2) 
	{
		Location currLoc = allTrips2.get(0);
		ArrayList<Location> tempArray = new ArrayList<Location>();
		tempArray.add(currLoc);
		
		for(Location e : allTrips2)
		{
			if(allTrips.indexOf(e) != 0 || allTrips2.indexOf(e) == allTrips2.size())
			{
				if(e.getName().compareTo(currLoc.getName()) != 0)
				{
					currLoc = allTrips2.get(allTrips2.indexOf(e));
					tempArray.add(currLoc);
				}
			}
		}
		
		return tempArray;
	}
	
	private static ArrayList<Episode> groupByPattern(ArrayList<Location> locFiltered) 
	{
		ArrayList<Episode> allPatterns = new ArrayList<Episode>();
		
		for(int x = 0; x < locFiltered.size()-1; x++)
		{
			Location one = locFiltered.get(x);
			Location two = locFiltered.get(x+1);
			
			Episode p = new Episode (one, two);
			allPatterns.add(p);
		}
		
		return allPatterns;
	}
	
	private static HashMap<Episode, Integer> countTrips(ArrayList<Episode> patterns)
	{
		HashMap<Episode, Integer> patternMap = new HashMap <Episode, Integer>();
		
		for(Episode p : patterns)
		{
			if(patternMap.containsKey(p))
			{
				int x = patternMap.get(p);
				patternMap.put(p, x+1);
			}
			else
			{
				patternMap.put(p, 1);
			}
		}
		
		return patternMap;
	}
	
	private static Date epochToDate(String timestamp) 
	{
		Date date = new Date(Long.parseLong(timestamp));
		return date;
	}

	public static Date getPatient1EndTime() {
		return patient1EndTime;
	}

	public static void setPatient1EndTime(Date patient1EndTime) {
		LocationDBParser.patient1EndTime = patient1EndTime;
	}

	public static Date getPatient2EndTime() {
		return patient2EndTime;
	}

	public static void setPatient2EndTime(Date patient2EndTime) {
		LocationDBParser.patient2EndTime = patient2EndTime;
	}

	public static Date getPatient3EndTime() {
		return patient3EndTime;
	}

	public static void setPatient3EndTime(Date patient3EndTime) {
		LocationDBParser.patient3EndTime = patient3EndTime;
	}

	public static Date getPatient4EndTime() {
		return patient4EndTime;
	}

	public static void setPatient4EndTime(Date patient4EndTime) {
		LocationDBParser.patient4EndTime = patient4EndTime;
	}

	public static Date getPatient5EndTime() {
		return patient5EndTime;
	}

	public static void setPatient5EndTime(Date patient5EndTime) {
		LocationDBParser.patient5EndTime = patient5EndTime;
	}
	
	
}
